-- 32 bit version program counter
-- bowmanb

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.typeDefinitions.all;

entity programCounter is
  port
    (
      clk        : in  std_logic;
      nReset     : in  std_logic;
      memWait    : in  std_logic;
      sel        : in  pcSel;
      jumpAddr   : in  std_logic_vector (25 downto 0);
      busA       : in  std_logic_vector (31 downto 0);
      pcOld      : in  std_logic_vector(31 downto 0);
      halt       : in  std_logic;
      pcplusfour : out std_logic_vector (31 downto 0);
      pcout      : out std_logic_vector (31 downto 0)
      );
end programCounter;

architecture programCounter_arch of programCounter is
  
  signal stall                                                 : std_logic;
  signal add4, add4_old, extend, adj, extadd, pcselout, pccurr : std_logic_vector(31 downto 0);

  component pc
    port (
      clk     : in  std_logic;
      nReset  : in  std_logic;
      halt    : in  std_logic;
      default : in  std_logic_vector(31 downto 0);
      pcin    : in  std_logic_vector(31 downto 0);
      pcout   : out std_logic_vector(31 downto 0));
  end component;

  component pcExtAdd
    port
      (
        -- Write data input port    
        offset : in  std_logic_vector (31 downto 0);
        pcin   : in  std_logic_vector (31 downto 0);
        -- read port 2
        pcout  : out std_logic_vector (31 downto 0)
        );
  end component;

  component pcExt
    port
      (
        -- Write data input port    
        imm   : in  std_logic_vector (15 downto 0);
        -- read port 2
        pcout : out std_logic_vector (31 downto 0)
        );
  end component;

  component pcAdj
    port
      (
        -- Write data input port    
        imm   : in  std_logic_vector (25 downto 0);
        pcin  : in  std_logic_vector (31 downto 0);
        -- read port 2
        pcout : out std_logic_vector (31 downto 0)
        );
  end component;

  component fouradder
    port (
      A   : in  std_logic_vector(31 downto 0);
      Sum : out std_logic_vector(31 downto 0)
      );
  end component;

  
begin

  pcout <= pccurr;

  pcExtAdd_c : pcExtAdd port map (
    offset => extend,
    pcin   => add4_old,
    pcout  => extadd);

  pcExt_c : pcExt port map (
    imm   => jumpAddr(15 downto 0),
    pcout => extend);

  pc_c : pc port map (
    clk => clk, nReset => nReset , default => x"00000000", halt => stall, pcin => pcselout, pcout => pccurr);

  pcplusfour <= add4;

  stall <= halt or memWait;

  pcSel : process (sel, add4, extadd, adj, busA)
  begin  -- process pcSel
    case sel is
      when pc_add4 =>
        pcselout <= add4;
      when pc_ext =>
        pcselout <= extAdd;
      when pc_adj =>
        pcselout <= adj;
      when pc_busA =>
        pcselout <= busA;
      when others =>
        pcselout <= (others => '0');
    end case;
  end process pcSel;

  fouradder_c : fouradder port map (
    A   => pccurr,
    Sum => add4);

  fouradderold_c : fouradder port map (
    A   => pcOld,
    Sum => add4_old);

  pcAdj_c : pcAdj port map (
    imm   => jumpAddr,
    pcin  => pcOld,
    pcout => adj);

end programCounter_arch;
